package com.hulizuofang.wol.chat.client.presenter;

import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;
import com.gwtplatform.dispatch.shared.DispatchAsync;
import com.gwtplatform.mvp.client.View;
import com.gwtplatform.mvp.client.annotations.NameToken;
import com.gwtplatform.mvp.client.annotations.ProxyCodeSplit;
import com.gwtplatform.mvp.client.proxy.PlaceRequest;
import com.gwtplatform.mvp.client.proxy.ProxyPlace;
import com.hulizuofang.wol.channel.client.ChannelManager;
import com.hulizuofang.wol.chat.client.action.LoginAction;
import com.hulizuofang.wol.chat.client.action.LoginResult;
import com.hulizuofang.wol.chat.client.action.LoginResult.LoginResultWorker;
import com.hulizuofang.wol.chat.client.action.SendChatAction;
import com.hulizuofang.wol.chat.client.action.SendChatResult;
import com.hulizuofang.wol.chat.client.action.SendChatResult.SendChatResultWorker;
import com.hulizuofang.wol.chat.client.data.ChatUser;
import com.hulizuofang.wol.chat.client.data.ChatUserIndex;
import com.hulizuofang.wol.chat.client.place.NameTokens;
import com.hulizuofang.wol.chat.client.ui.event.changeplace.ChangePlaceEvent;
import com.hulizuofang.wol.chat.client.ui.event.receive.ReceiveChatEvent;
import com.hulizuofang.wol.chat.client.ui.event.receive.ReceiveChatHandler;
import com.hulizuofang.wol.chat.client.ui.event.selectuser.SelectUserEvent;
import com.hulizuofang.wol.chat.client.ui.event.selectuser.SelectUserHandler;
import com.hulizuofang.wol.chat.client.ui.event.sendmessage.SendMessageEvent;
import com.hulizuofang.wol.chat.client.ui.event.sendmessage.SendMessageHandler;
import com.hulizuofang.wol.chat.client.ui.event.whoisonline.WhoisOnlineEvent;
import com.hulizuofang.wol.chat.client.ui.event.whoisonline.WhoisOnlineHandler;

public class WhoisOnlinePagePresenter extends AbstractNestedPresenter<WhoisOnlinePagePresenter.PageView, WhoisOnlinePagePresenter.PageProxy> {
	private static final Logger logger = Logger.getLogger(WhoisOnlinePagePresenter.class.getName());
	private final ChannelManager channelManager;

	private ChatUser chatUser = null;
	private final ChatUserIndex chatUserIndex;
	
	public ChatUser getChatUser() {
		return chatUser;
	}

	public void setChatUser(ChatUser chatUser) {
		this.chatUser = chatUser;
	}

	@Inject
	public WhoisOnlinePagePresenter(EventBus eventBus, PageView view, PageProxy proxy, DispatchAsync dispatcher, ChannelManager channelManager, ChatUserIndex chatUserIndex) {
		super(eventBus, view, proxy, dispatcher);
		this.channelManager = channelManager;
		this.chatUserIndex = chatUserIndex;
	}
	
	@ProxyCodeSplit
	@NameToken(NameTokens.WHOIS_ONLINE)
	public interface PageProxy extends ProxyPlace<WhoisOnlinePagePresenter> {
	}
	
	public interface PageView extends View {
		void refreshOnlineUser(Set<ChatUser> users);
		void showUser(ChatUser user);
		void openChat(ChatUser sender);
		void addMyMessage(ChatUser recipient, String message);
		void addOtherMessage(ChatUser sender, String message);
		void addErrorMessage(ChatUser recipient, String message, String error);
		void addUndeliveredMessage(ChatUser recipient, String message);
	}
	
	@Override
	public void onBind() {
		getEventBus().addHandler(WhoisOnlineEvent.getType(), new WhoisOnlineHandler() {
			@Override
			public void onUpdateWhoisOnline(WhoisOnlineEvent event) {
				Set<ChatUser> users = event.getUsers();
				getView().refreshOnlineUser(users);
				chatUserIndex.update(users);
			}
		});
		getEventBus().addHandler(SelectUserEvent.getType(), new SelectUserHandler() {
			@Override
			public void onSelectUser(SelectUserEvent event) {
				getView().openChat(event.getChatUser());
			}
		});
		getEventBus().addHandler(ReceiveChatEvent.getType(), new ReceiveChatHandler() {
			@Override
			public void onReceive(ReceiveChatEvent event) {
				getView().addOtherMessage(event.getSender(), event.getMessage());
			}
		});
		getEventBus().addHandler(SendMessageEvent.getType(), new SendMessageHandler() {
			@Override
			public void onSend(final SendMessageEvent event) {
				SendChatAction action = new SendChatAction(getChatUser(), event.getRecipient(), event.getMessage());
				getDispatcher().execute(action, new AsyncCallback<SendChatResult>() {
					@Override
					public void onFailure(Throwable caught) {
						getView().addErrorMessage(event.getRecipient(), event.getMessage(), caught.getMessage());
					}

					@Override
					public void onSuccess(SendChatResult result) {
						result.workResult(new SendChatResultWorker() {
							@Override
							public void work(boolean delivered) {
								if (delivered) {
									getView().addMyMessage(event.getRecipient(), event.getMessage());
								} else {
									getView().addUndeliveredMessage(event.getRecipient(), event.getMessage());
								}
							}
						});
					}
				});
			}
		});
	}

	@Override
	protected void onReveal() {
		LoginAction action = new LoginAction(getLogin());
		getDispatcher().execute(action, new AsyncCallback<LoginResult>() {
			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Login fails !");
				logger.log(Level.SEVERE, "", caught);
				ChangePlaceEvent.fire(getEventBus(),new PlaceRequest(NameTokens.START).with(NameTokens.LOGIN, getLogin()));
			}
			
			@Override
			public void onSuccess(LoginResult result) {
				result.workResult(new LoginResultWorker() {
					@Override
					public void work(ChatUser user, String token, Set<ChatUser> onlineUser) {
						getView().showUser(user);
						setChatUser(user);
						channelManager.addChannel(token);
						WhoisOnlineEvent.fire(getEventBus(), onlineUser);
					}
				});
			}
		});
	}
}
